﻿#include "TextVoiceReaderUI.h"
#include "ui_TextVoiceReaderUI1.h"
#include "ui_TextVoiceReaderUI2.h"

TextVoiceReaderUI::TextVoiceReaderUI(QWidget *parent) : QMainWindow(parent),
    settings_(QSettings::IniFormat, QSettings::UserScope, "Xairy", "TextVoiceReader"), translator_(nullptr), lastLine_(0), lastLineHeight_(0)
{
    int theme = settings_.value("theme").toInt();

    QActionGroup *agroup1 = new QActionGroup(this);
    switch (theme) {
    case 1: {
        auto ui2 = new Ui::TextVoiceReaderUI2;
        ui2->setupUi(this);
        ui = new Ui::TextVoiceReaderUI1;
        *ui = *(reinterpret_cast<Ui::TextVoiceReaderUI1*>(ui2));

        agroup1->addAction(ui->actionBlue_Style);
        agroup1->addAction(ui->actionWindows_Default);
        ui->actionWindows_Default->setChecked(true);
        delete ui2;
        break;
    }
    case 0: //如果是0就默认为2
    case 2: {
        ui = new Ui::TextVoiceReaderUI1;
        ui->setupUi(this);
        agroup1->addAction(ui->actionBlue_Style);
        agroup1->addAction(ui->actionWindows_Default);
        ui->actionBlue_Style->setChecked(true);
        break;
    }
    }
    ui->widget_2->hide();
    translator_ = new QTranslator(this);
    translator_->load(QLocale::Chinese, ":/images/cn.qm");
    ui->menuBar->installEventFilter(this);
    ui->plainTextEdit->viewport()->installEventFilter(this);

    auto view = new QListView();
    view->setFont(ui->comboBox->font());
    ui->comboBox->setView(view);

    if (ui->SystemButtons->isVisibleTo(ui->SystemButtons->parentWidget())) {
        this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);
        this->setAttribute(Qt::WA_TranslucentBackground);
    }

    connect(&textSpeak_, SIGNAL(doSpeakBuffer(QByteArray, QString)), &voicePlayer_, SLOT(onPlay(QByteArray)), Qt::QueuedConnection);
    connect(&voicePlayer_, SIGNAL(doPlayDone()), this, SLOT(onSelectTextToSpeak()), Qt::QueuedConnection);


    if (FAILED(::CoInitialize(NULL))) {
        return;
    }

    IEnumSpObjectTokens *tokens = nullptr;
    auto hr = SpEnumTokens(SPCAT_VOICES, nullptr, nullptr, &tokens);
    if( FAILED(hr)) {
        return;
    }
    QStringList voices;
    ULONG count = 0;
    tokens->GetCount(&count);
    for (ULONG i = 0; i < count; ++i) {
        ISpObjectToken *token = nullptr;
        tokens->Item(i, &token);

        wchar_t *temp = nullptr;
        SpGetDescription(token, &temp);
        voices << QString::fromWCharArray(temp);
    }

    ui->comboBox->blockSignals(true);
    ui->comboBox->addItems(voices);
    ui->comboBox->blockSignals(false);

    ui->plainTextEdit->setCursorWidth(3);

    if (ui->comboBox->count() <= 0)
        return;

    int rate = settings_.value("rate").toInt();
    ui->spinBox->setValue(rate);

    auto volumeVar = settings_.value("volume");
    if (volumeVar.isNull()) {
        volumeVar = 100;
    }
    int volume = volumeVar.toInt();
    ui->spbVolume->setValue(volume);

    QString voice = settings_.value("voice").toString();
    if (voice.isEmpty()) {
        ui->comboBox->setCurrentIndex(0);
        textSpeak_.setVoice(ui->comboBox->currentText());
    } else {
        int index = ui->comboBox->findText(voice, Qt::MatchExactly);
        ui->comboBox->setCurrentIndex(index);
        textSpeak_.setVoice(voice);
    }

    QActionGroup *agroup = new QActionGroup(this);
    agroup->addAction(ui->actionChinese);
    agroup->addAction(ui->actionEnglish);
    int language = settings_.value("language").toInt();
    switch (language) {
    case QLocale::Chinese: {
        ui->actionChinese->setChecked(true);
        on_actionChinese_triggered(true);
        break;
    }
    case QLocale::English: {
        ui->actionEnglish->setChecked(true);
        on_actionEnglish_triggered(true);
        break;
    }
    }

    trayIcon_.setIcon(QIcon(":/images/logo.ico"));
    trayIcon_.show();

    QMenu *menuTray = new QMenu(this);
    actionPlay_ = menuTray->addAction(tr("Play"), ui->pushButton, SLOT(click()));
    connect(ui->pushButton, SIGNAL(toggled(bool)),
            this, SLOT(onPlayToggled()), Qt::QueuedConnection);
    actionExit_ = menuTray->addAction(tr("Exit"), this, SLOT(onExitApp()));
    trayIcon_.setContextMenu(menuTray);

    connect(&trayIcon_, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            this, SLOT(onTrayReason(QSystemTrayIcon::ActivationReason)));


#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
    //针对qt4 bug的处理.
    ui->menuBar->installEventFilter(this);
#endif
}

TextVoiceReaderUI::~TextVoiceReaderUI()
{
    trayIcon_.hide();
    delete ui;
}


void TextVoiceReaderUI::on_actionOpenFile_triggered()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Select Text File"), ".", tr("Text files (*.txt)"));
    if (fileName.isEmpty())
        return;
    this->openFile(fileName);
}

void TextVoiceReaderUI::on_comboBox_currentIndexChanged(const QString &arg1)
{
    textSpeak_.setVoice(arg1);
    settings_.setValue("voice", arg1);
    settings_.sync();
}

void TextVoiceReaderUI::on_spinBox_valueChanged(int arg1)
{
    textSpeak_.setRate(arg1);
    settings_.setValue("rate", arg1);
    settings_.sync();
}

void TextVoiceReaderUI::on_pushButton_toggled(bool checked)
{
    ui->plainTextEdit->setReadOnly(checked);

    if (checked) {
        ui->pushButton->setText(tr("Stop"));
        this->selectTextToSpeak();
    } else {
        ui->pushButton->setText(tr("Play"));
    }
}

void TextVoiceReaderUI::selectTextToSpeak()
{
    if (!ui->pushButton->isChecked()) {
        return;
    }

    QTextCursor cursor = ui->plainTextEdit->textCursor();
    if (cursor.isNull())
        return;
    int index = cursor.position();
    QRegExp regexp("\\W");
    regexp.setMinimal(true);

    QTextDocument *document = ui->plainTextEdit->document();
    QTextCursor cursorNew = document->find(regexp, cursor);

    if (cursorNew.isNull()) {
        if (ui->plainTextEdit->document()->characterCount() - index <= 1) {

            ui->pushButton->setChecked(false);
            return;
        }
        cursor.setPosition(ui->plainTextEdit->document()->characterCount() - 1);
        ui->plainTextEdit->setTextCursor(cursor);
    } else {
        cursor = cursorNew;
    }

    int end = cursor.position();
    cursor.setPosition(index);
    cursor.setPosition(end, QTextCursor::KeepAnchor);
    ui->plainTextEdit->setTextCursor(cursor);
    QString text = cursor.selectedText();

    text.remove(regexp);
    if (text.isEmpty()) {
        selectTextToSpeak();
        return;
    }

    if (lastLine_ != 0 && cursor.blockNumber() != lastLine_) {
        int valueOffset = cursor.blockNumber() - lastLine_;
        int value = ui->plainTextEdit->verticalScrollBar()->value();
        ui->plainTextEdit->verticalScrollBar()->setValue(value + valueOffset + lastLineHeight_);
    }
    lastLine_ = cursor.blockNumber();
    lastLineHeight_ = cursor.block().lineCount() - 1;

    qDebug() << "selected text:" << text;
    textSpeak_.speak(text + " ");


    settings_.beginGroup(QCryptographicHash::hash(currrentFileName_.toLocal8Bit(), QCryptographicHash::Md5).toHex());
    settings_.setValue("last", end);
    settings_.sync();
    settings_.endGroup();
}

void TextVoiceReaderUI::openFile(const QString &fileName, QTextCodec *codecDefault)
{
    QFile file(fileName);
    if (file.size() > 50 * 1024 * 1024) {
        QMessageBox::warning(this, tr("Warning"), tr("File is too large to open."));
        return;
    }

    if (!file.open(QIODevice::ReadOnly))
        return;

    //精度的丢失程度
    static QMap<QByteArray, int> codecInfos;
    const QString original = QString::fromWCharArray(L"这是一段中亠︼﹄﹂ˉ︾︺﹀︸︶︵︷︿︹︽_﹁﹃︻】【」「}{〕〔》《］［（）〈〉‹›﹛﹜『』〖〗㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ❶❷❸❹❺❻❼❽❾❿①②③④⑤⑥⑦⑧⑨⑩⑳⑲⑱⑰⑯⑮⑭⑬⑫⑪⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑½⅓⅔¼¾⅛⅜⅝⅞∴∵∷ΝΞΟΠΡΣΤΥΦΧΨΩㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐāáǎàōóǒò衤罒覀夂癶耂牜虍歺糹釒飠㈈㈉㈊㈋㈌㈍㈎㈏㈐㈑㈒㈓ㅱㅲㅳㅴㅵㅶㅷㅸㅹㅺㅻㅼi:ə:a:ɔ:u:ieæəʌɔuあいうえおかきくけこさしユヨラリルレロワヲン゛゜┞┟┠┡┢┦┧┨┩┪╉╊✈✁〠〄♝♞◕†‡¬￢✌㏠㏡㏢㏣㏤㏥㏦㏧㏨㏩㏪㏫ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛ");
    QTextCodec *codecUtf8 = QTextCodec::codecForName("utf-8");
    const QByteArray byteArray = codecUtf8->fromUnicode(original);

    if (codecInfos.isEmpty() && codecDefault == nullptr) {
        QList<QByteArray> codecs = QTextCodec::availableCodecs();
        QActionGroup *group = new QActionGroup(this);
        qSort(codecs);
        for (int i = 0; i < codecs.length(); ++i) {
            QByteArray codeName = codecs.at(i);
            QTextCodec *codec = QTextCodec::codecForName(codeName);
            QTextCodec::ConverterState state;
            QByteArray bytesDecoded = codec->fromUnicode(original);
            QString textRecoded = codec->toUnicode(bytesDecoded, bytesDecoded.size(), &state);

            int sameCount = 0;
            for (int j = 0; j < original.length() && j < textRecoded.length(); ++j) {
                if (original.at(j) == textRecoded.at(j)) {
                    ++sameCount;
                }
            }
            codecInfos.insert(codeName, sameCount);
            QAction *action = ui->menuEncoding->addAction(codeName, this, SLOT(onChangeEncoding()));
            action->setObjectName(codeName);
            action->setCheckable(true);
            action->setActionGroup(group);
        }
    }

    QByteArray dataContent = file.read(byteArray.size());
    file.seek(0);

    QMultiMap<int, QByteArray> validCodecs;
    bool containsSystem = false;
    QList<QByteArray> codecs = QTextCodec::availableCodecs();
    for (int i = 0; i < codecs.length() && codecDefault == nullptr; ++i) {
        QByteArray codeName = codecs.at(i);
        QTextCodec *codec = QTextCodec::codecForName(codeName);

        QTextStream stream(dataContent);
        stream.setCodec(codec);
        QString codedStr1 = stream.read(100);//100QChar

        //获取到对应编码所对应的字节长度.
        QByteArray converted = codec->fromUnicode(codedStr1);
        int len = converted.size();
        QByteArray readed = dataContent.mid(0, len);

        QTextCodec::ConverterState state;
        QString codedStr2 = codec->toUnicode(readed.data(), readed.size(), &state);

        //转换没有出问题, 貌似很多字符集转换都不会出问题.
        if (state.invalidChars != 0 || state.remainingChars != 0) {
            continue;
        }

        if (converted == readed && codedStr1 == codedStr2) {
            int sameCount = codecInfos[codeName];
            //所以进行精度丢失排序, 让丢失精度最小的那个优先.
            validCodecs.insert(sameCount, codeName);
            if (codeName.toLower() == "system") {
                containsSystem = true;
            }
            continue;
        }
    }

    QTextStream stream(&file);
    QTextCodec *codec =  codecDefault;
    if (validCodecs.count() > 0 && codecDefault == nullptr) {
        if (containsSystem) {
            qDebug() << "system";
            codec = QTextCodec::codecForName("system");
            stream.setCodec(codec);
        } else {
            const QByteArray &codecName = (validCodecs.end() - 1).value();
            qDebug() << codecName;
            codec = QTextCodec::codecForName(codecName);
            stream.setCodec(codec);
        }
    } else {
        if (codecDefault == nullptr) {
            codec = QTextCodec::codecForName("system");
        }
        stream.setCodec(codec);
    }
    if (codecDefault == nullptr) {
        QAction *action = ui->menuEncoding->findChild<QAction*>(codec->name());
        if (action != nullptr) {
            action->setChecked(true);
        }
    }

    qDebug() << "stream:" << stream.codec()->name();
    QString textContent = stream.readAll();
    qDebug() << textContent.length();

    file.close();
    ui->plainTextEdit->setPlainText(textContent);

    settings_.beginGroup(QCryptographicHash::hash(fileName.toLocal8Bit(), QCryptographicHash::Md5).toHex());
    QString fileNameLast = settings_.value("file").toString();
    if (fileNameLast != fileName) {
        settings_.setValue("file", fileName);
        settings_.sync();
        QTextCursor cursor = ui->plainTextEdit->textCursor();
        cursor.setPosition(0);
        ui->plainTextEdit->setTextCursor(cursor);

    } else {
        int posLast = settings_.value("last").toInt();
        QTextCursor cursor = ui->plainTextEdit->textCursor();
        cursor.setPosition(posLast);
        ui->plainTextEdit->setTextCursor(cursor);
    }
    lastLine_ = 0;
    ui->plainTextEdit->setFocus();

    currrentFileName_ = fileName;
    settings_.endGroup();
}

void TextVoiceReaderUI::on_actionFind_triggered()
{
    emit doBreakLastFindWindow();

    QTimer::singleShot(0, this, SLOT(onShowFindDialog()));
}


void TextVoiceReaderUI::on_actionSave_triggered()
{
    if (currrentFileName_.isEmpty())
        return;

    QFile file(currrentFileName_);
    if (!file.open(QIODevice::WriteOnly)) {
        return;
    }
    QTextStream stream(&file);
    stream.setGenerateByteOrderMark(true);
    stream << ui->plainTextEdit->toPlainText();
    file.close();
}

void TextVoiceReaderUI::on_spbVolume_valueChanged(int arg1)
{
    textSpeak_.setVolume(arg1);
    settings_.setValue("volume", arg1);
    settings_.sync();
}

void TextVoiceReaderUI::onExitApp()
{
    qApp->exit();
}

void TextVoiceReaderUI::onChangeEncoding()
{
    QAction *action = (QAction*)this->sender();
    QByteArray code = action->text().toLocal8Bit();
    QTextCodec *codec = QTextCodec::codecForName(code);
    openFile(currrentFileName_, codec);
}

void TextVoiceReaderUI::onSelectTextToSpeak()
{
    selectTextToSpeak();
}

void TextVoiceReaderUI::onTrayReason(QSystemTrayIcon::ActivationReason reason)
{
    if (reason == QSystemTrayIcon::Context) {
        trayIcon_.contextMenu()->show();
    } else if (reason == QSystemTrayIcon::DoubleClick) {
        this->show();
    }
}

void TextVoiceReaderUI::onPlayToggled()
{
    actionPlay_->setText(ui->pushButton->text());
}

void TextVoiceReaderUI::onShowFindDialog()
{
    FindTextDialog dialog(this, ui->plainTextEdit);
    dialog.show();

    QEventLoop loop;
    connect(&dialog, SIGNAL(accepted()),
            &loop, SLOT(quit()));
    connect(&dialog, SIGNAL(rejected()),
            &loop, SLOT(quit()));
    connect(this, SIGNAL(doBreakLastFindWindow()),
            &loop, SLOT(quit()));
    loop.exec();
}

void TextVoiceReaderUI::onSpeakProcess(int index)
{
    QObject *obj = this->sender();
    QEventLoop *loop = (QEventLoop*)(obj->property("loop").toLongLong());
    ui->progressText->setText(QString::number(index) + "/" + QString::number(content_.length()));
    ui->progressBar->setValue(index);

    if (index == content_.length()) {
        loop->exit();
    }
}

void TextVoiceReaderUI::onStartRequest()
{
//    auto cursor = ui->plainTextEdit->textCursor();
//    int position = cursor.position();
//    position -= 300; //后移, 接一部分头
//    cursor.setPosition(position);
//    ui->plainTextEdit->setTextCursor(cursor);
    this->selectTextToSpeak();
    this->selectTextToSpeak();
    this->selectTextToSpeak();
    this->selectTextToSpeak();
    this->selectTextToSpeak();
}

void TextVoiceReaderUI::closeEvent(QCloseEvent *e)
{
    e->ignore();
    this->hide();
}

void TextVoiceReaderUI::resizeEvent(QResizeEvent *e)
{
    QMainWindow::resizeEvent(e);
    int x = this->width() - ui->SystemButtons->width();
    ui->SystemButtons->move(x, 0);

}


bool TextVoiceReaderUI::eventFilter(QObject *obj, QEvent *e)
{
    if (obj == ui->menuBar && e->type() == QEvent::MouseButtonPress) {
        ReleaseCapture();
        SendMessage(reinterpret_cast<HWND>(this->winId()), WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 5);
    } else if (obj == ui->menuBar && e->type() == QEvent::MouseButtonDblClick) {
        ui->btnMaxNormal->click();
    } else if (obj == ui->plainTextEdit->viewport() && e->type() == QEvent::Drop) {
        QDropEvent *de = dynamic_cast<QDropEvent*>(e);
        if (de->mimeData()->hasUrls()) {
            auto urls = de->mimeData()->urls();
            if (!urls.isEmpty()) {
                this->openFile(urls.first().toLocalFile());
                return true;
            }
        }
    }
    if (obj == ui->menuBar && e->type() == QEvent::MouseButtonPress) {
        //Qt4无边框窗口 菜单存在问题.
        QSize size = ui->menuBar->size();
        QSize sizeMax = ui->menuBar->maximumSize();
        ui->menuBar->setMaximumSize(size.width() - 1, size.height());
        ui->menuBar->resize(size.width() - 1, size.height());
        QEventLoop loop;
        QTimer::singleShot(10, &loop, SLOT(quit()));
        loop.exec();
        ui->menuBar->setMaximumSize(sizeMax);
        ui->menuBar->resize(size);
        QTimer::singleShot(10, &loop, SLOT(quit()));
        loop.exec();
    }
    return QMainWindow::eventFilter(obj, e);
}

void TextVoiceReaderUI::on_actionSaveAudio_triggered()
{
    QString fileWavName = QFileDialog::getSaveFileName(this, tr("Save Audio File"), ".", tr("Mp3 file (*.mp3);;Wave file (*.wav)"));
    if (fileWavName.isEmpty())
        return;

    ui->widget->hide();
    ui->widget_2->show();
    ui->menuBar->setEnabled(false);
    ui->plainTextEdit->setEnabled(false);
    ui->progressBar->setValue(0);

    content_ = ui->plainTextEdit->toPlainText();
    ui->progressBar->setMaximum(content_.size());
    ui->progressText->setText("0/" + QString::number(content_.length()));

    {
        QEventLoop loop;
        connect(this, SIGNAL(doBreakGenerateWav()), &loop, SLOT(quit()));
        textSpeak_.disconnect(&voicePlayer_);
        GenerateAudioFile generator(&textSpeak_, content_);
        generator.setProperty("loop", (qint64)&loop);

        connect(&generator, SIGNAL(doSpeakProgress(int)),
                this, SLOT(onSpeakProcess(int)), Qt::QueuedConnection);

        generator.init(ui->spinBox->value(),  ui->spbVolume->value(), ui->comboBox->currentText(), fileWavName);

        loop.exec();
        generator.release();
    }

    connect(&textSpeak_, SIGNAL(doSpeakBuffer(QByteArray)), &voicePlayer_, SLOT(onPlay(QByteArray)), Qt::QueuedConnection);

    ui->menuBar->setEnabled(true);
    ui->plainTextEdit->setEnabled(true);
    ui->widget_2->hide();
    ui->widget->show();
}

void TextVoiceReaderUI::on_btnStopGenerate_clicked()
{
    emit doBreakGenerateWav();
}

void TextVoiceReaderUI::on_actionExit_triggered()
{
    emit doBreakLastFindWindow();
    emit doBreakGenerateWav();
    qApp->exit();
}

void TextVoiceReaderUI::on_actionChinese_triggered(bool checked)
{
    if (!checked) {
        return;
    }
    qApp->installTranslator(translator_);
    ui->retranslateUi(this);
    settings_.setValue("language", static_cast<int>(QLocale::Chinese));
    settings_.sync();
}

void TextVoiceReaderUI::on_actionEnglish_triggered(bool checked)
{
    if (!checked) {
        return;
    }
    qApp->removeTranslator(translator_);
    ui->retranslateUi(this);
    settings_.setValue("language", static_cast<int>(QLocale::English));
    settings_.sync();
}

void TextVoiceReaderUI::on_btnClose_clicked()
{
    this->hide();
}


void TextVoiceReaderUI::on_btnMin_clicked()
{
    this->showMinimized();
}

void TextVoiceReaderUI::on_btnMaxNormal_toggled(bool checked)
{
    if (checked) {
        this->showMaximized();
    } else {
        this->showNormal();
    }
}

void TextVoiceReaderUI::on_actionWindows_Default_triggered()
{
    settings_.setValue("theme", 1);
    settings_.sync();
    int ret = QMessageBox::information(this, tr("Info"), tr("Restart now?"), QMessageBox::Yes | QMessageBox::No);
    if (ret == QMessageBox::Yes) {
        QProcess::startDetached(qApp->arguments().first());
        qApp->exit();
    }
}

void TextVoiceReaderUI::on_actionBlue_Style_triggered()
{
    settings_.setValue("theme", 2);
    settings_.sync();
    int ret = QMessageBox::information(this, tr("Info"), tr("Restart now?"), QMessageBox::Yes | QMessageBox::No);
    if (ret == QMessageBox::Yes) {
        QProcess::startDetached(qApp->arguments().first());
        qApp->exit();
    }
}

void TextVoiceReaderUI::on_actionStartServer_triggered(bool checked)
{
    if (checked) {
        QMessageBox::information(this, tr("Tips"), tr("Listen on address 0.0.0.0:8080. \nUse http://127.0.0.1:8080 to access."));

        this->textSpeak_.disconnect(&voicePlayer_);
        lanAudioServer_ = QSharedPointer<LanAudioServer>(new LanAudioServer(&textSpeak_));
        connect(&textSpeak_, SIGNAL(doSpeakBuffer(QByteArray, QString)), lanAudioServer_.data(), SLOT(onResponseBytes(QByteArray, QString)), Qt::DirectConnection);
        connect(lanAudioServer_.data(), SIGNAL(doResponed()), this, SLOT(onSelectTextToSpeak()), Qt::QueuedConnection);
        connect(lanAudioServer_.data(), SIGNAL(doStartRequest()), this, SLOT(onStartRequest()), Qt::QueuedConnection);

        ui->pushButton->blockSignals(true);
        ui->pushButton->setChecked(true);
        ui->pushButton->blockSignals(false);
    } else {
        ui->pushButton->blockSignals(true);
        ui->pushButton->setChecked(false);
        ui->pushButton->blockSignals(false);
        lanAudioServer_.clear();
    }
}


void TextVoiceReaderUI::on_actionAbout_Qt_triggered()
{
    QApplication::aboutQt();
}

void TextVoiceReaderUI::on_actionAbout_TVR_triggered()
{
    QRegExp regexp("PRODUCTVERSION (\\d+,\\d+,\\d+,\\d+)");
    QFile file(":/images/res.rc");
    if (!file.open(QIODevice::ReadOnly))
        return;
    QTextStream stream(&file);
    stream.setCodec("UTF-16LE");
    QString content = stream.readAll();
    file.close();

    int index = regexp.indexIn(content);
    if (index == -1)
        return;
    QString text = regexp.cap(1);
    text.replace(",", ".");

    QMessageBox::information(this, tr("About Text Voice Reader"), "version:" + text + "                      ");
}
